#include "time_module.h"
#include "retcodes.h"
#include "log.h"

namespace common
{

	STimeWheel::STimeWheel( )
	{
		spoke_index = 0;
	}

	STimeWheel::~STimeWheel( )
	{
	}

	CTimeModule::CTimeModule( )
	{
		cur_ms_ = 0;
		cur_sec_ = 0;
		delta_time_ = 0;
		time_offset_ = 0;
		cur_frame_ = 0;
		time_deviation_ = 0;
	}

	CTimeModule::~CTimeModule( )
	{
	}

	int32_t CTimeModule::Initialize( int64_t cur_ms )
	{
		cur_ms_ = cur_ms + time_offset_;
		cur_sec_ = cur_ms_/1000;
		return SUCCEED;
	}

	int32_t CTimeModule::Finalize( )
	{
		return SUCCEED;
	}

	int32_t CTimeModule::RegisterTimer( ITimer& timer )
	{
		int64_t interval = ( ( timer.activetime( ) - cur_ms_ ) >> GRANULARITY_BITS );
		if ( interval <= 1 )
		{
			interval = 1;
		}
		for ( int i = 0; i < WHEEL_NUM; ++i )
		{
			if ( interval < WHEEL_SIZE )
			{
				STimeWheel& wheel = wheels_[ i ];
				uint32_t spokeindex = ( ( wheel.spoke_index + interval ) & WHEEL_MASH );
				timer.list_link( ).LinkAfter( wheel.spokes[ spokeindex ] );
				return SUCCEED;
			}
			else
			{
				interval >>= WHEEL_BITS;
			}
		}
		return ERR_UNKNOWN;
	}

	int32_t CTimeModule::UnregisterTimer( ITimer& timer )
	{
		timer.list_link( ).Unlink( );	
		return SUCCEED;
	}

	void CTimeModule::TickUpdate( int64_t cur_ms )
	{
		delta_time_ = cur_ms + time_offset_ - cur_ms_;
		cur_ms_ = cur_ms + time_offset_;
		cur_sec_ = cur_ms_/1000;
		cur_frame_++;
		STimeWheel& wheel = wheels_[ 0 ];
		int32_t loopnum = ( delta_time_  >> GRANULARITY_BITS );

		// 累计时间差值, 当累计到一个GRANULARITY_BITS时候计算的timer loop + 1
        time_deviation_ += delta_time_ % ( 1 << GRANULARITY_BITS );
        if( ( time_deviation_ >> GRANULARITY_BITS ) >= 1 ) 
        {   
            loopnum += time_deviation_ >> GRANULARITY_BITS ;
            time_deviation_ = time_deviation_ % ( 1 << GRANULARITY_BITS );
        } 


		for ( int32_t i = 0; i < loopnum; ++i )
		{
			if ( ++wheel.spoke_index >= WHEEL_SIZE )
			{
				wheel.spoke_index = 0;
				Cascade( 1 );
			}
			CListLink< ITimer >& listlink = wheel.spokes[ wheel.spoke_index ];
			CListLink< ITimer >* next_node = listlink.next_node( );
			while ( NULL != next_node )
			{
				next_node->Unlink( );
				ITimer* timer = next_node->parent( );
				if( NULL != timer )
				{
					timer->Active( );
				}
				next_node = listlink.next_node( );
			}
		}
	}

	void CTimeModule::Cascade( uint32_t index )
	{
		if ( NULL == wheels_ || index >= WHEEL_NUM )
		{
			LOG_INFO("default", "cascade index:%u", index );
			return;
		}
		STimeWheel& wheel = wheels_[ index ];
		if ( ++wheel.spoke_index >= WHEEL_SIZE )
		{
			wheel.spoke_index = 0;
			Cascade( index + 1 );
		}
		CListLink< ITimer >& listlink = wheel.spokes[ wheel.spoke_index ];
		CListLink< ITimer >* next_node =  listlink.next_node( );
		while ( NULL != next_node )
		{
			next_node->Unlink( );
			ITimer* timer = next_node->parent( );
			if( NULL != timer )
			{
				RegisterTimer( *timer );
			}
			next_node = listlink.next_node( );
		}
	}

	int32_t CTimeModule::ResetTime( int64_t ms )
	{
		time_offset_ = ms - cur_ms_ + time_offset_;
		cur_ms_ = ms;
		cur_sec_ = cur_ms_/1000;
		//重置所有的timer;
		CListLink< ITimer > timer_link;
		for( int32_t i = 0; i < WHEEL_NUM; ++i )
		{
			STimeWheel& wheel = wheels_[ i ];	
			for( int32_t j = 0; j < WHEEL_SIZE; ++j )
			{
				CListLink< ITimer >& spoke = wheel.spokes[ j ];
				CListLink< ITimer >* timer_node = spoke.next_node( );
				while( NULL != timer_node )
				{
					timer_node->LinkAfter( timer_link );
					timer_node = spoke.next_node( );
				}
			}
		}
		CListLink< ITimer >* cursor = timer_link.next_node( );
		while( cursor != NULL )
		{
			ITimer* timer = cursor->parent( );	
			if( NULL != timer )
			{
				RegisterTimer( *timer );
			}
			cursor = timer_link.next_node( );
		}
		return 0;
	}

	int32_t CTimeModule::week_day() const
	{
		time_t sec = cur_sec();
		tm* t = localtime(&sec);
		if (t == NULL)
		{
			return 0;
		}
		return t->tm_wday;
	}
	//20180614去掉时分秒，尽量别用这种，直接用CUR_SEC存时间戳
	int32_t CTimeModule::cur_day()
	{
		time_t sec = cur_sec();
		tm* t = localtime(&sec);
		if (t == NULL)
		{
			return 0;
		}
		return (t->tm_year + 1900) * 10000
			+ (t->tm_mon + 1) * 100
			+ t->tm_mday;
	}
	//时分秒，尽量别用这种，直接用CUR_SEC存时间戳
	int32_t CTimeModule::cur_hms()
	{
		time_t sec = cur_sec();
		tm* t = localtime(&sec);
		if (t == NULL)
		{
			return 0;
		}
		return (t->tm_hour * 10000
			+ t->tm_min * 100
			+ t->tm_sec);
	}
	//1806141444？18年6月14号14时44分，尽量别用这种，直接用CUR_SEC存时间戳
	int32_t CTimeModule::cur_fullday()
	{
		time_t sec = cur_sec();
		tm* t = localtime(&sec);
		if (t == NULL)
		{
			return 0;
		}
		return ((t->tm_year - 100) * 100000000
			+ (t->tm_mon + 1) * 1000000
			+ t->tm_mday * 10000
			+ t->tm_hour * 100
			+ t->tm_min);
	}

	uint32_t CTimeModule::GetDeadlineTime(uint32_t min)
	{
		uint32_t mins = 0;
		uint32_t hours = 0;
		uint32_t days = 0;
		uint32_t deadtime = 0;

		//	计算传入分钟数进位基数
		if (min > 60)
		{
			mins = min % 60;
			hours = min / 60 % 24;
			days = min / (24 * 60);
		}

		int32_t cur_fullday_ = cur_fullday();
		//	计算截至时间
		if (mins + cur_fullday_ % 100 > 60)
		{
			//	新增加小时数
			uint32_t add_hour = 0;
			add_hour = (mins + cur_fullday_ % 100) / 60;

			//	更新分钟数
			mins = (mins + cur_fullday_ % 100) % 60;
			cur_fullday_ = (cur_fullday_ / 100) * 100 + mins;// + mins

																		//	更新小时数和天数
			uint32_t cur_hours = (cur_fullday_ / 100) % 100;
			hours = hours + add_hour;
			if (hours + cur_hours > 24)
			{
				days = hours + cur_hours / 24;
				hours = hours % 24;
			}
		}

		//	更新小时数和天数并得到截止时间
		deadtime = cur_fullday_ + days * 10000 + hours * 100;// + days + hours
		return deadtime;
	}

	bool CTimeModule::IsSameDayOfMonth(uint32_t day)
	{
		time_t sec = cur_sec();
		tm* t = localtime(&sec);
		if (t == NULL)
		{
			return false;
		}

		return t->tm_mday == day;
	}

	bool CTimeModule::IsSameDayOfWeek(uint32_t day)
	{
		time_t sec = cur_sec();
		tm* t = localtime(&sec);
		if (t == NULL)
		{
			return false;
		}

		return t->tm_wday == day;
	}

}
